import socket
from threading import Thread
import time
import json
#联机端口IP设置
ADDRESS = ('127.0.0.1',8712)
#设置最大玩家
MaxPlayer = 5
 
g_socket_server = None
debug = False
 
g_conn_pool = {}
def init():
    global g_socket_server
    g_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
    g_socket_server.bind(ADDRESS)
    g_socket_server.listen(5)
    print("[INFO] Game server start,wait for client connecting...")
    print('[INFO] Server running at '+ADDRESS[0]+':'+str(ADDRESS[1]))

def accept_client():
    while True:
        client, info = g_socket_server.accept()
        thread = Thread(target=send_Msg, args=(client, info))
        thread.setDaemon(True)
        thread.start()
 
Chicken_POS = {}
Egg_POS = []
Score = 0
bottle = 0
def uploadERROR(client,msg):
    time.sleep(2)
    try:
        client.send(
            json.dumps(
                {
                    'CMD':'ERROR',
                    'data':msg
                }
            ).encode(encoding='utf8')
        )
    except OSError as e:
        print(e)
        
def send_Msg(client, info):
    global Chicken_POS,Egg_POS,bottle,Score
    while True:
        try:
            bytes = client.recv(1024)
            msg = bytes.decode(encoding='utf8')
            jd = json.loads(msg)
            if debug:
                print('[INFO] Recv:'+msg)
            cmd = jd['CMD']
            client_type = jd['client_type']
            data = jd['data']
            if 'CONNECT' == cmd:
                #判断联机人数
                if len(g_conn_pool) > MaxPlayer:
                    uploadERROR(client,'服务端连接人数太多')
                if client_type in g_conn_pool:
                    uploadERROR(client,'重复的连接名')
                    client.close()
                else:
                    init_config = {
                        'CMD':'SENDCONFIG',
                        'data':{'chicken':Chicken_POS,'egg':Egg_POS,'score':Score,'bottle':bottle}
                    }
                    client.send(json.dumps(init_config).encode(encoding='utf8'))
                    g_conn_pool[client_type] = client
                    print('[INFO] on client connect: ' + client_type, info)
            elif 'SENDSCORE' == cmd:
                smsg = {"CMD":"SENDSCORE","data":data}
                Score = int(data)
                for i in g_conn_pool:
                    g_conn_pool[i].send(json.dumps(smsg).encode(encoding='utf8'))

            elif 'UPCHICKEN' == cmd:
                Chicken_POS[client_type] = data
                for i in g_conn_pool:
                    g_conn_pool[i].send(json.dumps(
                        {
                            'CMD':'PLAYERS',
                            'data':Chicken_POS
                        }
                    ).encode(encoding='utf8'))

            elif 'UPEGG' == cmd:
                Egg_POS = data
                for i in g_conn_pool:
                    g_conn_pool[i].send(json.dumps(
                        {
                            'CMD':'EGGS',
                            'data':Egg_POS
                        }
                    ).encode(encoding='utf8'))
            
            elif 'SENDSBOTTLE' == cmd:
                smsg = {"CMD":"SENDSBOTTLE","data":data}
                bottle = int(data)
                for i in g_conn_pool:
                    g_conn_pool[i].send(json.dumps(smsg).encode(encoding='utf8'))

        except Exception as e:
            if debug:
                print(e)
            try:
                remove_client(client_type)
            except:
                print('[ERRO] An internal error has occurred')
            break
        
        

def remove_client(client_type):
    global Chicken_POS
    try:
        client = g_conn_pool[client_type]
        if None != client:
            client.close()
            g_conn_pool.pop(client_type)
            del Chicken_POS[client_type]
            print("[WARN] client offline: " + client_type)
    except KeyError:
        del Chicken_POS[client_type]
        print('[ERRO] The client is forcibly disconnected. Procedure')

if __name__ == '__main__':
    init()
    thread = Thread(target=accept_client)
    thread.setDaemon(True)
    thread.start()
    while True:
        time.sleep(0.1)
